<?php
/*
	Copyright 2006-2007 Alex Djachenko http://www.my-site.ru
	Authors: Alex Djachenko
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

class sharpobj_storage_mysql_flex extends sharpobj_storage_mysql
{
	private $protoobj;

	// *******************************
	// Базовый набор функций работы с записями
	// *******************************
    /**
     * Получить запись по ее id
     *
     * @param int $id
     * @return bool
     */
    function get($id)
	{
		$idobj = $this->id2obj($id);
	
		if ($idobj->get('plain')==0)
		{    // Неправильный id
		    return false;
		}
		if (is_null($this->protoobj))
		{
			// Объект формата не установлен
			// Создаем объект для результата
			$dataobj = new sharpobj_data_item_data();
			// Формируем SQL-запрос
			$sql = 'SELECT * FROM #!table#'
					." WHERE `rid`='{$idobj->get('sql')}'";
			$mysqlres = $this->sqlquery($sql,'sqlres');
			// Проверяем наличие результата
			if (false===$mysqlres)
			{	// Результат отсутствует
				return false;
			}
			// Просматриваем результат
			while ($res = mysql_fetch_array($mysqlres))
			{
				$dataobj->set('rdata',$res);
			}
		}else
		{
			// Хранилище было инициализировано объектом с форматом
			// Создаем объект для результата
			$dataobj = $this->getObj();
			// Получаем формат данных
			$rdata = $dataobj->get('rdata',null,array('noempty'=>false,'novalue'=>true));
			// Просматриваем все элементы и выбираем данные
			foreach ($rdata as $rval)
			{
				// Формируем SQL-запрос
				$sql = 'SELECT * FROM #!table#'
					." WHERE `rid`='{$idobj->get('sql')}'"
					." AND `name`='{$rval['name']}' LIMIT 1";
				$mysqlres = $this->sqlquery($sql,'assocvalue');
				if($mysqlres === false)
				{
				    continue;
				}
				// Добавляем данные в объект
				$dataobj->set('sql',$mysqlres['value'],$mysqlres['name']);
			}
		}
		// Устанавливаем id записи
		$dataobj->setId($idobj->get('plain'));
		return $dataobj;	
	}
    /**
     * Вставить запись в базу данных
     *
     * @param sharpobj_data_interface_item $data
     */
    function insert(sharpobj_data_item_data $data)
	{
		// Формируем SQL-запрос

		if ($data->getId()<1)
		{
			// Ошибка: не указан id
			mst_error('Не передан id',"Для операции INSER в хранилище mysqlflex необходимо задать id записи "
			."вместе с данными",1);
			return false;
		}
		if ($this->sqlquery("SELECT count(*) FROM #!table# WHERE `rid`='{$data->getId()}'",'onevalue'))
		{
			mst_error('id не уникален',"Для операции INSER в хранилище mysqlflex необходимо задать уникальный id записи "
			."вместе с данными",1);
			return false;
		}
		if (is_null($this->protoobj))
		{
			// Формат данных не задан
			$rdata = $data->get('rdata');
			
		}else
		{
			// Формат данных задан
			$rdata = $this->getObj()->get('rdata',null,array('noempty'=>false,'novalue'=>true));
		}
		foreach ($rdata as $row)
		{
			if (is_null($this->protoobj))
			{
				// Формат данных не задан
				$value = $row['value'];
			}else
			{
				// Формат данных задан
				$row2 = $data->get('rdata',stripslashes($row['name']));
				$value = $row2['value'];
			}
			$sql = "INSERT INTO #!table# (`rid`,`name`,`type`,`value`)"
						." VALUES ('{$data->getId()}',"
						."'{$row['name']}','{$row['type']}',{$value})";
			$this->sqlquery($sql,'action');
		}
		return $this->id2obj($data->getId());
	}
	
    /**
     * Обновить запись с $id
     * Если $emptyreplace == true - пустые записи тоже обновляются
     * Если $id == null - id береться из контейнера
     *
     * @param int $id
     * @param sharpobj_data_interface_item $data
     * @param bool $emptyreplace
     * @param sharpobj_data_interface_item $data
     */
    function update(sharpobj_data_item_data $data,$id=null,$emptyreplace=false)
	{
		// Создаем контейнер для id
		$idobj = $this->id2obj($id);
		
		if ($idobj->get('plain')>0)
		{
			// ID задан принудительно
			// $idobj->set('plain',$id);
		}elseif ($data instanceof sharpobj_data_item_data  AND $data->getId()>0)
		{
			// ID задан в объекте
			$idobj = new sharpobj_data_item_int();
			$idobj->set('plain',$data->getId());
		}else
		{
			mst_error('Не передан id',"Для операции UPDATE необходимо задать id записи "
			."принудительно или передать вместе с контейнером",1);
			return false;
		}
		
		if ($emptyreplace)
		{
			$data->setId($idobj->get('plain'));
			$this->delete($idobj);
			return $this->insert($data);
		}else
		{
			if (is_null($this->protoobj))
			{
				// Формат данных не задан
				$rdata = $data->get('rdata');
			}else
			{
				// Формат данных задан
				$rdata = $this->getObj()->get('rdata',null,array('noempty'=>false,'novalue'=>true));
			}
			foreach ($rdata as $row)
			{
				if (is_null($this->protoobj))
				{
					// Формат данных не задан
					$value = $row['value'];
				}else
				{
					// Формат данных задан
					$row2 = $data->get('rdata',stripslashes($row['name']));
					$value = $row2['value'];
				}
				// Удаление старой записи
				$sql = "DELETE FROM #!table# WHERE `rid`={$idobj->get('sql')}"
						." AND `name`='{$row['name']}' LIMIT 1";
				$this->sqlquery($sql,'action');
				// Вставка новой записи
				$sql = "INSERT INTO #!table# (`rid`,`name`,`type`,`value`) "
							."VALUES ({$data->getId()},'{$row['name']}','{$row['type']}',$value)";
				$this->sqlquery($sql,'action');
			}
			return true;		
		}
		
	}
    /**
     * Удалить запись по ее id
     *
     * @param int $id
     * @return bool
     */
    function delete($id)
	{
		// $idobj = new sharpobj_data_item_int();
		// $idobj->set('plain',$id);
		$idobj = $this->id2obj($id);
		// Формируем SQL-запрос
		$sql = 'DELETE FROM #!table#'
		.' WHERE `rid`='."'".$idobj->get('sql')."'";
		// echo $sql;
		return $this->sqlquery($sql,'action');
	}

	function count()
	{
		return intval($this->sqlquery("SELECT count(DISTINCT `rid`) FROM #!table#",'onevalue'));
		// $count = mysql_num_rows($res );//GROUP BY `rid` sqlres
		// mysql_free_result($res);
		// return $count;
	}
	/**
	 *  Получить список всех записей в БД	
	 * @return void
	 */
	function getListAll($from=null,$limit=null)
	{
		//
		return $this->sqlqueryList("SELECT `rid` FROM #!table# GROUP BY `rid` "
			.$this->sqlgenLimit($from,$limit));
	}
	// *******************************
	// Дополнительные функции работы с записями
	// *******************************
	function countUp($id,$field)
	{
		//
		$field = addslashes($field);
		// Создаем контейнер для id
		$idobj = $this->id2obj($id);
		if ($idobj->get('plain')<=0)
		{
			mst_error('Не передан id',
					"Для операции countUp необходимо задать id записи ",1);
			return false;
		}
		return $this->sqlquery("UPDATE #!table# "
						." SET `value`=(`value`+1) "
						." WHERE `rid`='{$idobj->get('sql')}'"
						." AND `name`='{$field}'",'action');		
	}
	function countDown($id,$field)
	{
		//
		$field = addslashes($field);
		// Создаем контейнер для id
		$idobj = $this->id2obj($id);
		if ($idobj->get('plain')<=0)
		{
			mst_error('Не передан id',
					"Для операции countUp необходимо задать id записи ",1);
			return false;
		}
		return $this->sqlquery("UPDATE #!table# "
						." SET `value`=(`value`-1) "
						." WHERE `rid`='{$idobj->get('sql')}'"
						." AND `name`='{$field}'",'action');		
	}		
	// *******************************
	// Дополнительные функции, для работы с sql-БД
	// *******************************
    /**
     * Выбрать список объектов из базы по sql-запросу
     * В первой колонке должны идти ID записей в данном хранилище
     * Остальные поля не важны
     * @param string $sql
     */	
    function sqlqueryList($sql)
	{
		// Создаем контейнер для результата
		$result = new sharpobj_data_item_array();
		// Выполняем запрос к БД
		if (!($sqlres = $this->sqlquery($sql,'sqlres')))
		{
			return $result;
		}
		while ($res = mysql_fetch_row($sqlres))
		{
			//
			$result->add(null,$this->get($res[0]));
			// echo $res[0];
		}
		// Очищаем результат запроса
		mysql_free_result($sqlres);
		return $result;
	}

	// *******************************
	// Вспомогательные функции
	// *******************************
	function getObj($datapath=null)
	{
		return clone $this->protoobj;
	}
	/**
	 * Возвращаем дамп для создания базы данных
	 * @return string (sql)
	 */
	function sqlDBCreate()
	{
		//
		return "CREATE TABLE {$this->tbname()} \n"
				."(\n"
  					."`id` int(11) NOT NULL auto_increment,\n"
  					."`rid` int(11) NOT NULL,\n"
  					."`name` varchar(255) collate utf8_unicode_ci NOT NULL,\n"
 					."`type` varchar(255) collate utf8_unicode_ci NOT NULL,\n"
 					."`value` varchar(255) collate utf8_unicode_ci default NULL,\n"
					."PRIMARY KEY  (`id`),\n"
					."UNIQUE KEY `rid` (`rid`,`name`),\n"
					."KEY `rid_2` (`rid`)\n"
				.") \n"
				."ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
	}
	/**
	 * Создать таблицу в БД
	 */
	function createTable()
	{
		return $this->sqlquery($this->sqlDBCreate(),'action');
	}
	// *******************************
	// Служебные функции для внутреннего пользования
	// *******************************
	function __construct(sharpobj_data_interface_item $protoobj=null,$opt)
	{
		$this->protoobj = $protoobj;
		$this->tbname = $opt['tbname'];
		$this->idfield = @$opt['idfield'];
		// Добавляем соединение по умолчанию (потом можно переопределить)
		$this->setConnection(sharpobj_dbconn_get('mysql'));
	}	


}
?>